package com.dji.pa.cluster.db.dataSouce;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.jdbc.datasource.AbstractDataSource;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

/**
 * 集群代理数据源
 *
 *  
 *
 */
public abstract class AbstractClusterDataSource extends AbstractDataSource implements InitializingBean {
    private static final Logger log = LoggerFactory.getLogger(AbstractClusterDataSource.class);
	/**
	 * 读服务器列表
	 */
	private List<Server> readDBList;
	/**
	 * 写服务器
	 */
	private List<Server> writeDBList;
	/**
	 * 模板数据源
	 */
	private String templetDataSource;

	/**
	 * 当前线程使用的数据源
	 */
	private ThreadLocal<Server> holder = new ThreadLocal<Server>();
	/**
	 * 读写分离+异常恢复
	 */
	private DataSourceProcessor processor;

	public void afterPropertiesSet() throws Exception {
		if (!StringUtils.hasText(templetDataSource)) {
			AbstractClusterDataSource.log.error("未指定模板库，多数据源将根据URL参数进行初始化和此模板进行配置");
			System.exit(-1);
		}
		if (CollectionUtils.isEmpty(readDBList) && !CollectionUtils.isEmpty(writeDBList)) {
			AbstractClusterDataSource.log.error("读库和写库至少要指定一个");
			System.exit(-1);
		}
		List<Server> readAndWriteDBList = new ArrayList<Server>();
		readAndWriteDBList.addAll(readDBList);
		readAndWriteDBList.retainAll(writeDBList);// 可读可写列表
		readDBList.removeAll(readAndWriteDBList);// 只保留可读列表
		writeDBList.removeAll(readAndWriteDBList);// 只保留可写列表
		for (Server item : readDBList) {
			item.setServerType(Server.READ);
			item.setDataSource(creatDataSource(item.getIpAndPort()));
		}
		for (Server item : writeDBList) {
			item.setServerType(Server.WRITE);
			item.setDataSource(creatDataSource(item.getIpAndPort()));
		}
		for (Server item : readAndWriteDBList) {
			item.setServerType(Server.READWRITE);
			item.setDataSource(creatDataSource(item.getIpAndPort()));
		}
		readDBList.addAll(readAndWriteDBList);
		writeDBList.addAll(readAndWriteDBList);
	}

	public abstract DataSource creatDataSource(String ipAndPort);

	public Connection getConnection() throws SQLException {
		DataSource dataSouce = processor.getMatchServer().getDataSource();
		return dataSouce == null ? null : dataSouce.getConnection();
	}

	public Connection getConnection(String username, String password) throws SQLException {
		DataSource dataSouce = processor.getMatchServer().getDataSource();
		return dataSouce == null ? null : dataSouce.getConnection(username, password);
	}

	public ThreadLocal<Server> getHolder() {
		return holder;
	}

	public List<Server> getReadDBList() {
		return readDBList;
	}

	public String getTempletDataSource() {
		return templetDataSource;
	}

	public List<Server> getWriteDBList() {
		return writeDBList;
	}

	public void setHolder(ThreadLocal<Server> holder) {
		this.holder = holder;
	}

	public void setProcessor(DataSourceProcessor processor) {
		this.processor = processor;
	}

	public void setReadDBList(Vector<Server> readDBList) {
		this.readDBList = readDBList;
	}

	public void setTempletDataSource(String templetDataSource) {
		this.templetDataSource = templetDataSource;
	}

	public void setWriteDBList(Vector<Server> writeDBList) {
		this.writeDBList = writeDBList;
	}
}